﻿using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Diagnostics.CodeAnalysis;

namespace Microsoft.Office.OneNote
{
    [DebuggerDisplay("{Name}")]
    [TypeConverter(typeof(OneNoteColorConverter))]
    public struct OneNoteColor : IEquatable<OneNoteColor>
    {
        private const string NoneString = "none";
        private const string AutomaticString = "automatic";

        private readonly uint? _value;

        private OneNoteColor(uint value)
        {
            _value = value;
        }

        [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "A")]
        public byte A
        {
            get { return GetComponent("A", 0xff000000, 24); }
        }

        [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "R")]
        public byte R
        {
            get { return GetComponent("R", 0xff0000, 16); }
        }

        [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "G")]
        public byte G
        {
            get { return GetComponent("G", 0xff00, 8); }
        }

        [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "B")]
        public byte B
        {
            get { return GetComponent("B", 0xff, 0); }
        }

        public string Name
        {
            get
            {
                const BindingFlags PublicStatic = BindingFlags.Public | BindingFlags.Static;
                OneNoteColor self = this;

                return (from field in GetType().GetFields(PublicStatic)
                        where (field.GetValue(null)).Equals(self)
                        select field.Name).SingleOrDefault() ?? ToString();
            }
        }

        private byte GetComponent(string name, uint mask, int shift)
        {
            VerifyNotAutomatic(name);

            uint value = _value.Value;

            return (byte)((value & mask) >> shift);
        }

        public override int GetHashCode()
        {
            return _value.GetHashCode();
        }

        public bool Equals(OneNoteColor other)
        {
            return _value.Equals(other._value);
        }

        public override bool Equals(object obj)
        {
            if (obj is OneNoteColor)
            {
                return Equals((OneNoteColor)(obj));
            }

            return false;
        }

        public override string ToString()
        {
            if (_value.HasValue)
            {
                if (A != 0)
                {
                    return string.Format(CultureInfo.InvariantCulture,
                        "#{0:X2}{1:X2}{2:X2}", R, G, B);
                }

                return NoneString;
            }

            return AutomaticString;
        }

        private void VerifyNotAutomatic(string component)
        {
            if (_value == null)
            {
                string message = string.Format(CultureInfo.CurrentUICulture,
                    Exceptions.Messages._CannotGetAutomaticColorComponent, component);

                throw new InvalidOperationException(message);
            }
        }


        public static readonly OneNoteColor Automatic = new OneNoteColor();
        public static readonly OneNoteColor None = new OneNoteColor(0x00FFFFFF);
        public static readonly OneNoteColor Blue = new OneNoteColor(0xFF8AA8E4);
        public static readonly OneNoteColor Yellow = new OneNoteColor(0xFFFFD869);
        public static readonly OneNoteColor Green = new OneNoteColor(0xFFB7C997);
        public static readonly OneNoteColor Red = new OneNoteColor(0xFFEE9597);
        public static readonly OneNoteColor Purple = new OneNoteColor(0xFFB49EDE);
        public static readonly OneNoteColor Cyan = new OneNoteColor(0xFF91BAAE);
        public static readonly OneNoteColor Orange = new OneNoteColor(0xFFF6B078);
        public static readonly OneNoteColor Magenta = new OneNoteColor(0xFFD5A4BB);
        public static readonly OneNoteColor BlueMist = new OneNoteColor(0xFF9BBBD2);
        public static readonly OneNoteColor PurpleMist = new OneNoteColor(0xFFAB9CB7);
        public static readonly OneNoteColor Tan = new OneNoteColor(0xFFE8D199);
        public static readonly OneNoteColor Lemon = new OneNoteColor(0xFFF5F96F);
        public static readonly OneNoteColor Apple = new OneNoteColor(0xFFADE792);
        public static readonly OneNoteColor Teal = new OneNoteColor(0xFF4DBCCA);
        public static readonly OneNoteColor RedChalk = new OneNoteColor(0xFFBA7575);
        public static readonly OneNoteColor Silver = new OneNoteColor(0xFF9595AA);

        public static bool operator ==(OneNoteColor left, OneNoteColor right)
        {
            return left.Equals(right);
        }

        public static bool operator !=(OneNoteColor left, OneNoteColor right)
        {
            return !left.Equals(right);
        }

        [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Argb")]
        public static OneNoteColor FromArgb(byte alpha, byte red, byte green, byte blue)
        {
            return new OneNoteColor(((uint)alpha) << 24 | ((uint)red) << 16 | ((uint)green) << 8 | (uint)blue);
        }

        [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Rgb")]
        public static OneNoteColor FromRgb(byte red, byte green, byte blue)
        {
            return FromArgb(byte.MaxValue, red, green, blue);
        }
    }
}
